package cn.chinaunicom.woplus.openapi.spring;

import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

public class WoPlusClient {
	static org.apache.log4j.Logger logger=org.apache.log4j.Logger.getLogger(WoPlusClient.class);
	
	/**
	 * @param appKey 		应用标识
	 * @param appSecret 	应用密钥
	 * */
	public WoPlusClient(String appKey,String appSecret){
		Authenticate.getInstance().config(appKey, appSecret).setHttpClient(this);
		
	}
	
	/**
	 * @param api_url API接口地址
	 * @param params 参数集
	 * @return 返回值 @see WoPlusResponse
	 * @exception 
	 * */
	public WoPlusResponse post(String api_url,Map<String,Object> params,boolean hasSign) throws Exception{
		Map<String,String> auth = Authenticate.getInstance().getAuthorization();
		if(auth==null) throw new Exception("Token is Null");
		
		if(hasSign){
			String secretKey=Authenticate.getInstance().getAppKey()+"&"+Authenticate.getInstance().getAppSecret();
			String signature = EMCSign.signValue(params, secretKey);
		
			params.put("signType", "HMAC-SHA1");
			params.put("signature", signature);
		}
		
		return postJSONEntity(api_url,auth,params);
	}
	public WoPlusResponse post(String api_url,Map<String,Object> params) throws Exception{
		return this.post(api_url, params,true);
	}
	
	/**
	 * @param api_url API接口地址
	 * @param params 参数集
	 * @param platform 平台ID
	 * @param password 平台密码
	 * 
	 * @return 返回值 @see WoPlusResponse
	 * @exception 
	 * */
	public WoPlusResponse post(String api_url,Map<String,Object> params,String platform,String password) throws Exception{
		
		Map<String,String> auth = Authenticate.getAuthorizationWithPlatform(platform, password);
		
		String secretKey=platform+"&"+password;
		String signature = EMCSign.signValue(params, secretKey);
		
		params.put("signType", "HMAC-SHA1");
		params.put("signature", signature);
		
		return postJSONEntity(api_url,auth,params);
		
	}
	/**
	 * @param api_url API接口地址
	 * @param params 参数集
	 * @return 返回值 @see WoPlusResponse
	 * @exception 
	 * */
	public WoPlusResponse get(String api_url,Map<String,Object> params) throws Exception{
		
		Map<String,String> auth = Authenticate.getInstance().getAuthorization();
		if(auth==null) throw new Exception("Token is Null");
		
		return getJSONEntity(api_url,auth,params);
		
	}
		
	private static synchronized WoPlusResponse _transObject(@SuppressWarnings("rawtypes") Map obj){
		
		WoPlusResponse resp = new WoPlusResponse();
		
		Map<String,Object> msg=new HashMap<String,Object>();
		
		for(Object k:obj.keySet()){
			if(k.toString().equals("resultCode")) 
				resp.resultCode=obj.get(k).toString();
			else if(k.toString().equals("resultDescription"))
				resp.resultDescription=obj.get(k).toString();
			else
				msg.put(k.toString(), obj.get(k));
		}
		resp.content=msg;
		
		return resp;
		
	}
	
	/**
	 * 根据api_url判断是否使用SSL
	 * 
	 * @param api_url API访问地址
	 * @return RestTemplate 
	 * */
	private RestTemplate getRestTemplate(String api_url) throws Exception {
		
		CloseableHttpClient httpclient=HttpClients.createDefault();
		
		if (api_url.startsWith("https")) {
			X509TrustManager xtm = new X509TrustManager() {
				public void checkClientTrusted(X509Certificate[] chain,
						String authType) throws CertificateException {
				}

				public void checkServerTrusted(X509Certificate[] chain,
						String authType) throws CertificateException {
				}

				public X509Certificate[] getAcceptedIssuers() {
					
					return new X509Certificate[]{};
					
				}
			};

			SSLContext sslContext = SSLContext.getInstance("TLS");
			sslContext.init(null, new TrustManager[] { xtm }, null);
			SSLContext.setDefault(sslContext);

			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
					sslContext,
					SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

			httpclient = HttpClients.custom().setSSLSocketFactory(sslsf)
					.build();
		}
		
		HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpclient);
		RestTemplate template = new RestTemplate(httpFactory);
		
		List<HttpMessageConverter<?>> messageConverters=new ArrayList<HttpMessageConverter<?>>();
		MappingJackson2HttpMessageConverter jsonMessageConverter=new MappingJackson2HttpMessageConverter();
		List<MediaType> supportedMediaTypes=new ArrayList<MediaType>();
		supportedMediaTypes.add(MediaType.APPLICATION_JSON);
		jsonMessageConverter.setSupportedMediaTypes(supportedMediaTypes);
		messageConverters.add(jsonMessageConverter);
		template.setMessageConverters(messageConverters);
		
		template.setErrorHandler(new ResponseErrorHandler(){

			public boolean hasError(ClientHttpResponse response)
					throws IOException {
				return false;
			}

			public void handleError(ClientHttpResponse response)
					throws IOException {
			}});
		
		return template;
	}
	
	
	WoPlusResponse postJSONEntity(String api_url,final Map<String,String> auth,Map<String,Object> params) throws Exception {
		
		HttpHeaders requestHeaders = new HttpHeaders(); 
		
		RestTemplate restTemplate=getRestTemplate(api_url);
		
		if(auth!=null && !auth.isEmpty()){
			StringBuilder sb=new StringBuilder();
			for(String k : auth.keySet()){
				sb.append(",")
				.append(k)
				.append("=\"")
				.append(auth.get(k))
				.append("\"");
			}
			requestHeaders.set("Authorization",sb.toString().substring(1));
		}
		requestHeaders.set("Content-Type", "application/json;charset=utf-8");
		requestHeaders.set("Accept","application/json");
		
		@SuppressWarnings("rawtypes")
		HttpEntity<Map> requestEntity = new HttpEntity<Map>(params,requestHeaders); 
		
		@SuppressWarnings("rawtypes")
		ResponseEntity<Map> response = 
				restTemplate.exchange(api_url, 
						HttpMethod.POST, 
						requestEntity, 
						Map.class); 
			
		if(response!=null && response.getBody()!=null){
			logger.debug(response.getBody());
			return _transObject(response.getBody());
			
		}
		else
			return null;
		
		
	}

	WoPlusResponse getJSONEntity(String api_url,Map<String,String> auth,Map<String,Object> params) throws Exception{
		
		RestTemplate restTemplate=getRestTemplate(api_url);
		HttpHeaders requestHeaders = new HttpHeaders(); 
		
		if(auth!=null && !auth.isEmpty()){
			StringBuilder sb=new StringBuilder();
			for(String k : auth.keySet()){
				sb.append(",")
				.append(k)
				.append("=\"")
				.append(auth.get(k))
				.append("\"");
			}
			requestHeaders.set("Authorization",sb.toString().substring(1));
		}
		
		requestHeaders.set("Content-Type", "application/json;charset=utf-8");
		requestHeaders.set("Accept","application/json");
		
		StringBuilder sb = new StringBuilder();
		sb.append(api_url);
		sb.append("?");
		for(String key:params.keySet()){
			sb.append(key)
			.append("=")
			.append(params.get(key))
			.append("&");
		}
		String full_api_url = sb.toString().substring(0, sb.toString().lastIndexOf("&"));
		
		@SuppressWarnings("rawtypes")
		ResponseEntity<Map> response = restTemplate.exchange(full_api_url, HttpMethod.GET, null, Map.class);
		
		if(response!=null && response.getBody()!=null){
			logger.debug(response.getBody());
			return _transObject(response.getBody());
		}
		
		return null;
	}
	
}
